<template>
  <div class="container">
    <h1>OCR with n8n</h1>
    <div class="split-panel">
      <div class="image-panel">
        <div class="panel-label-row">
          <span class="panel-label">请上传图片</span>
          <div class="img-actions" v-if="imageUrl">
            <zoom-in-outlined class="img-action-icon" @click.stop="showPreview = true" />
            <close-circle-outlined class="img-action-icon" @click.stop="handleClear" />
          </div>
        </div>
        <a-upload
          :show-upload-list="false"
          :before-upload="handleBeforeUpload"
          accept="image/*"
          class="image-upload"
          :disabled="loading"
        >
          <template #default="slotProps">
            <div class="image-upload-box" @click="slotProps && slotProps.open && slotProps.open()">
              <template v-if="imageUrl">
                <img :src="imageUrl" alt="预览" style="cursor: default;" />
              </template>
              <template v-else>
                <plus-outlined class="plus-icon" />
              </template>
            </div>
          </template>
        </a-upload>
        <div v-if="file" class="file-info">
          <div>文件名：{{ file.name }}</div>
          <div>文件大小：{{ formatSize(file.size) }}</div>
        </div>
        <a-modal v-model:open="showPreview" :footer="null" width="auto" :centered="true" :bodyStyle="{padding: '0', textAlign: 'center'}">
          <img :src="imageUrl" alt="图片预览" style="max-width:90vw; max-height:80vh; display:block; margin:auto;" />
        </a-modal>
      </div>
      <div class="center-panel">
        <a-button
          type="primary"
          :disabled="!file || loading"
          @click="handleRecognize"
          class="recognize-btn"
        >
          {{ loading ? '识别中...' : '开始识别' }}
        </a-button>
      </div>
      <div class="result-panel">
        <div class="panel-label-row">
          <span class="panel-label">识别内容</span>
          <div class="result-actions" v-if="result && !loading">
            <fullscreen-outlined class="result-action-icon" @click="showResultModal = true" />
            <copy-outlined class="result-action-icon" @click="handleCopyResult" />
            <close-circle-outlined class="result-action-icon" @click="handleClearResult" />
          </div>
        </div>
        <div :class="['result-box', loading ? 'loading-center' : '']">
          <template v-if="loading">
            <a-spin />
          </template>
          <template v-else-if="result">
            <pre>{{ result }}</pre>
          </template>
          <template v-else>
            <div class="result-placeholder">识别内容将在此显示</div>
          </template>
        </div>
        <div v-if="result && !loading" class="result-tip">本识别功能仅提供参考</div>
        <a-modal v-model:open="showResultModal" :footer="null" width="800px" :centered="true" :bodyStyle="{padding: '24px'}">
          <pre style="white-space: pre-wrap; text-align: left; font-size: 16px;">{{ result }}</pre>
        </a-modal>
        <div v-if="error" class="error">{{ error }}</div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { message } from 'ant-design-vue'
import { PlusOutlined, CloseCircleOutlined, ZoomInOutlined, FullscreenOutlined, CopyOutlined } from '@ant-design/icons-vue'
import { WEBHOOK_URL } from './config'

const file = ref(null)
const imageUrl = ref('')
const result = ref('')
const loading = ref(false)
const error = ref('')
const showPreview = ref(false)
const showResultModal = ref(false)

const formatSize = (size) => {
  if (size < 1024) return size + ' B'
  if (size < 1024 * 1024) return (size / 1024).toFixed(1) + ' KB'
  return (size / 1024 / 1024).toFixed(2) + ' MB'
}

const handleBeforeUpload = (f) => {
  file.value = f
  result.value = ''
  error.value = ''
  // 生成图片预览
  const reader = new FileReader()
  reader.onload = (e) => {
    imageUrl.value = e.target.result
  }
  reader.readAsDataURL(f)
  return false // 阻止自动上传
}

const handleClear = () => {
  file.value = null
  imageUrl.value = ''
  result.value = ''
  error.value = ''
}

const handleClearResult = () => {
  result.value = ''
  error.value = ''
}

const handleCopyResult = async () => {
  try {
    await navigator.clipboard.writeText(result.value)
    message.success('内容已复制')
  } catch {
    message.error('复制失败')
  }
}

const handleRecognize = async () => {
  if (!file.value) return
  loading.value = true
  error.value = ''
  result.value = ''
  try {
    const formData = new FormData()
    formData.append('data', file.value)
    const res = await fetch(WEBHOOK_URL, {
      method: 'POST',
      body: formData
    })
    if (!res.ok) throw new Error('Webhook 请求失败')
    const text = await res.text()
    let data
    try {
      data = JSON.parse(text)
      // 尝试提取文本内容
      if (
        Array.isArray(data) &&
        data[0]?.candidates?.[0]?.content?.parts?.[0]?.text
      ) {
        result.value = data[0].candidates[0].content.parts[0].text
      } else {
        result.value = JSON.stringify(data, null, 2)
      }
    } catch {
      result.value = text
    }
  } catch (e) {
    error.value = e.message || '识别失败'
  } finally {
    loading.value = false
  }
}
</script>

<style scoped>
.container {
  max-width: 800px;
  margin: 48px auto;
  background: #fff;
  border-radius: 16px;
  box-shadow: 0 4px 24px rgba(0, 80, 200, 0.08);
  padding: 32px 24px 24px 24px;
  text-align: center;
}
h1 {
  color: #1677ff;
  margin-bottom: 24px;
}
.split-panel {
  display: flex;
  flex-direction: row;
  gap: 16px;
  justify-content: center;
  align-items: flex-start;
}
.image-panel, .result-panel {
  background: #f0f7ff;
  border-radius: 8px;
  padding: 16px 16px 8px 16px;
  width: 260px;
  height: 340px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.center-panel {
  display: flex;
  align-items: center;
  height: 340px;
}
.panel-label-row {
  width: 100%;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}
.panel-label {
  color: #1677ff;
  font-weight: 500;
  font-size: 16px;
}
.image-upload {
  width: 100%;
}
.image-upload-box {
  width: 200px;
  height: 240px;
  background: #fff;
  border: 2px dashed #1677ff;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: border-color 0.2s;
  position: relative;
}
.image-upload-box:hover {
  border-color: #4096ff;
}
.image-upload-box img {
  max-width: 100%;
  max-height: 100%;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(22,119,255,0.08);
}
.plus-icon {
  font-size: 48px;
  color: #b0b8c9;
}
.file-info {
  width: 100%;
  margin-top: 8px;
  font-size: 13px;
  color: #666;
  text-align: left;
}
.img-actions {
  display: flex;
  gap: 8px;
}
.img-action-icon {
  font-size: 22px;
  color: #1677ff;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 1px 4px rgba(22,119,255,0.08);
  cursor: pointer;
  transition: color 0.2s;
}
.img-action-icon:hover {
  color: #ff4d4f;
}
.result-panel {
  position: relative;
}
.result-actions {
  display: flex;
  gap: 8px;
}
.result-action-icon {
  font-size: 22px;
  color: #1677ff;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 1px 4px rgba(22,119,255,0.08);
  cursor: pointer;
  transition: color 0.2s;
}
.result-action-icon:hover {
  color: #4096ff;
}
.result-box {
  width: 100%;
  height: 240px;
  background: #fff;
  color: #1a237e;
  text-align: left;
  overflow: auto;
  white-space: pre-wrap;
  border-radius: 8px;
  border: 1px solid #e6f0ff;
  padding: 12px;
  margin-top: 8px;
  display: flex;
  align-items: flex-start;
  justify-content: flex-start;
}
.result-box.loading-center {
  align-items: center;
  justify-content: center;
}
.result-placeholder {
  color: #b0b8c9;
  font-size: 16px;
  margin: auto;
}
.result-tip {
  width: 100%;
  margin-top: 8px;
  color: #999;
  font-size: 13px;
  text-align: left;
}
.recognize-btn {
  width: 120px;
  height: 40px;
  margin: 0 8px;
}
.error {
  color: #ff4d4f;
  position: absolute;
  bottom: 8px;
  left: 0;
  width: 100%;
  text-align: center;
}
</style>
